home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 398 / 398.xpi / chrome / forecastfox.jar / content / options / options.js < prev    next >
Text File  |  2010-02-04  |  29KB  |  882 lines

  1. /*------------------------------------------------------------------------------
  2.   Copyright (c) 2008 Ensolis, LLC. All Rights Reserved.
  3.   ----------------------------------------------------------------------------*/
  4.   
  5. var gOptions = null;
  6.  
  7. function optionsLoad()
  8. {
  9.   gOptions = new OptionsModule();
  10.   gOptions.start();
  11. }
  12.  
  13. function optionsUnload()
  14. {
  15.   gOptions.stop();
  16.   gOptions = null;
  17. }
  18.  
  19. function OptionsModule()
  20. {
  21.   this.wrappedJSObject = this;
  22.   return this;
  23. }
  24.  
  25. //XXX simplify code
  26. OptionsModule.prototype = {
  27.   _dskSvc: null,
  28.   _prfSvc: null,
  29.   _icnSvc: null,
  30.   _migSvc: null,
  31.   _max: null,
  32.   _errors: null,
  33.   
  34.   start: function OptionsModule_start()
  35.   {
  36.     //get the services
  37.     var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
  38.                  getService(Ci.ffIManagerService);
  39.     this._dskSvc = mgrSvc.disk;
  40.     this._prfSvc = mgrSvc.profiles;
  41.     this._icnSvc = mgrSvc.icons;
  42.     this._migSvc = mgrSvc.migrator;
  43.     
  44.     //setup the error array
  45.     this._errors = [];
  46.  
  47.     //stop rotating profiles
  48.     this._prfSvc.endRotating();
  49.     
  50.     //add observers      
  51.     var obs = Cc["@mozilla.org/observer-service;1"].
  52.               getService(Ci.nsIObserverService);
  53.     obs.addObserver(this, "forecastfox-profiles", false);
  54.     obs.addObserver(this, "forecastfox-icons", false);
  55.       
  56.     //setup the display for the prefs
  57.     this.populateProfiles();
  58.     this.populateOptions();
  59.     this.populateIcons(true);
  60.       
  61.     //enable-disable slider options
  62.     if (!checkAlertService()) {
  63.       document.getElementById("cc-slider").setAttribute("hidden", true);
  64.       document.getElementById("swa-slider").setAttribute("hidden", true);
  65.     }
  66.       
  67.     //set the validate labels
  68.     this.populateValidLabels();
  69.  
  70.     //select general page
  71.     var pages = document.getElementById("ff-list-pages");
  72.     pages.selectedItem = pages.childNodes[0];
  73.   },
  74.   
  75.   stop: function OptionsModule_stop()
  76.   {
  77.     //start rotating profiles
  78.     this._prfSvc.startRotating();
  79.  
  80.     //remove observers
  81.     try {
  82.       var obs = Cc["@mozilla.org/observer-service;1"].
  83.                 getService(Ci.nsIObserverService);
  84.       obs.removeObserver(this, "forecastfox-profiles");
  85.       obs.removeObserver(this, "forecastfox-icons");
  86.       obs = null;
  87.     } catch(e) {}
  88.     
  89.     //release references
  90.     this._dskSvc = null;
  91.     this._prfSvc = null;
  92.     this._icnSvc = null;
  93.     this._migSvc = null;    
  94.     this._max = null;
  95.     this._errors = null;
  96.   },
  97.   
  98.   checkLocid: function OptionsModule_checkLocid()
  99.   {
  100.     if (getPref("general.locid") == "00000") {
  101.       // switch to the first page
  102.       var list = document.getElementById("ff-list-pages");
  103.       list.selectedItem = list.childNodes[0];
  104.       this.switchPage(list);
  105.       
  106.       // then highlight the location id
  107.       var locid = document.getElementById("ff-text-code");
  108.       locid.focus();
  109.       locid.select();
  110.     }
  111.   },
  112.   
  113.   switchPage: function OptionsModule_switchPage(aList)
  114.   {
  115.     var deck = document.getElementById("ff-deck-pages");
  116.     var page = aList.selectedIndex;
  117.     deck.selectedIndex = page;  
  118.   },
  119.   
  120.   populateProfiles: function OptionsModule_populateProfiles()
  121.   {
  122.     var list = document.getElementById("ff-list-profs");
  123.     var popup = document.getElementById("ff-popup-profs");    
  124.     var id = this._prfSvc.current.ID;
  125.     var items = this._prfSvc.getItems({});
  126.     var item;
  127.  
  128.     //remove old profiles
  129.     while (popup.hasChildNodes())
  130.       popup.removeChild(popup.lastChild);
  131.     
  132.     //append new profiles     
  133.     for (var x=0; x<items.length; x++) {
  134.       item = document.createElement("menuitem");
  135.       item.setAttribute("id", items[x].ID);
  136.       item.setAttribute("label", items[x].name);
  137.       item.setAttribute("value", items[x].ID);
  138.       item.setAttribute("type", "prof");
  139.       popup.appendChild(item);
  140.       
  141.       if (items[x].ID == id)
  142.         list.selectedItem = item;
  143.     }
  144.     
  145.     // if the current profile isn't around, select the first
  146.     // one in the list, and switch profiles to it.
  147.     if (list.selectedItem == null) {
  148.       list.selectedItem = popup.firstChild;
  149.       this._prfSvc.current = this._prfSvc.getItem(list.selectedItem.getAttribute("value"));
  150.     }
  151.   },
  152.   
  153.   populateIcons: function OptionsModule_populateIcons(aRebuild)
  154.   {
  155.     var list = document.getElementById("ff-list-icons");
  156.     var id = this._icnSvc.current.ID;
  157.     var icons = this._icnSvc.getItems({});
  158.  
  159.     //save current
  160.     var save = null;
  161.     if (list.selectedIndex >= 0)
  162.       save = list.selectedItem.value;
  163.     else
  164.       save = id;
  165.       
  166.     //clear list
  167.     while (list.hasChildNodes() && aRebuild)
  168.       list.removeChild(list.lastChild); 
  169.          
  170.     //populate list    
  171.     for (var x = 0; x < icons.length; x++) {
  172.       var item = aRebuild ? list.appendItem(icons[x].name, icons[x].ID) : list.getItemAtIndex(x);
  173.     
  174.       //set selection
  175.       if (icons[x].ID == save) {
  176.          //XXX work around for bug 250123 (https://bugzilla.mozilla.org/show_bug.cgi?id=250123)
  177.          list.ensureElementIsVisible(item);
  178.          list.selectedItem = item;
  179.       }
  180.               
  181.       //set current
  182.       if (icons[x].ID == id)
  183.         item.setAttribute("icon", "true");
  184.       else
  185.         item.removeAttribute("icon");     
  186.     }  
  187.  
  188.     //set selected if not already
  189.     item = list.childNodes[0];    
  190.     if (list.selectedIndex < 0) {
  191.       list.selectedItem = item;
  192.     }
  193.     
  194.     //do select function
  195.     this.iconSelect();
  196.   },
  197.  
  198.   
  199.   populateOptions: function OptionsModule_populateOptions()
  200.   {
  201.     //general
  202.     this.setElement("ff-text-code", "general.locid", null);
  203.     this.setElement("ff-group-units", "units.current", "units");
  204.     this.populateBars();
  205.     this.populatePositions();
  206.   
  207.     //swa panel
  208.     this.setElement("ff-chk-swa-panel", "swa.panel.enabled", null);
  209.     this.setElement("ff-list-swa-panel-display", "swa.panel.display", "ff-popup-swa-panel-display");
  210.   
  211.     //swa tooltip 
  212.     this.setElement("ff-chk-swa-tooltip", "swa.tooltip.enabled", null);
  213.     this.setElement("ff-list-swa-tooltip-display", "swa.tooltip.display", "ff-popup-swa-tooltip-display");   
  214.   
  215.     //swa slider
  216.     this.setElement("ff-chk-swa-slider", "swa.slider.enabled", null);
  217.     this.setElement("ff-list-swa-slider-display", "swa.slider.display", "ff-popup-swa-slider-display");
  218.     this.setElement("ff-text-swa-slider", "swa.slider.freq", null);
  219.  
  220.     //radar panel
  221.     this.setElement("ff-chk-radar-panel", "radar.panel.enabled", null);
  222.     this.setElement("ff-list-radar-panel-display", "radar.panel.display", "ff-popup-radar-panel-display");
  223.   
  224.     //radar tooltip 
  225.     this.setElement("ff-chk-radar-tooltip", "radar.tooltip.enabled", null);
  226.     this.setElement("ff-list-radar-tooltip-display", "radar.tooltip.display", "ff-popup-radar-tooltip-display");
  227.     
  228.     //hourly panel
  229.     this.setElement("ff-chk-hbh-panel", "hbh.panel.enabled", null);
  230.     
  231.     //5 day panel
  232.     this.setElement("ff-chk-fiveday-panel", "fiveday.panel.enabled", null);
  233.         
  234.     //current panel
  235.     this.setElement("ff-chk-cc-panel", "cc.panel.enabled", null);
  236.     this.setElement("ff-list-cc-panel-display", "cc.panel.display", "ff-popup-cc-panel-display");
  237.   
  238.     //current tooltip 
  239.     this.setElement("ff-chk-cc-tooltip", "cc.tooltip.enabled", null);
  240.     this.setElement("ff-list-cc-tooltip-display", "cc.tooltip.display", "ff-popup-cc-tooltip-display");   
  241.   
  242.     //current slider
  243.     this.setElement("ff-chk-cc-slider", "cc.slider.enabled", null);
  244.     this.setElement("ff-list-cc-slider-display", "cc.slider.display", "ff-popup-cc-slider-display");
  245.     this.setElement("ff-text-cc-slider", "cc.slider.freq", null);
  246.   
  247.     //today's panel
  248.     this.setElement("ff-chk-dayt-panel", "dayt.panel.enabled", null);  
  249.     this.setElement("ff-list-dayt-panel-display", "dayt.panel.display", "ff-popup-dayt-panel-display");
  250.     this.setElement("ff-list-dayt-panel-mode", "dayt.panel.mode", "ff-popup-dayt-panel-mode");
  251.    
  252.     //today's tooltip
  253.     this.setElement("ff-chk-dayt-tooltip", "dayt.tooltip.enabled", null);
  254.     this.setElement("ff-list-dayt-tooltip-display", "dayt.tooltip.display", "ff-popup-dayt-tooltip-display");       
  255.   
  256.     //today's switch 
  257.     this.setElement("ff-list-dayt-switch", "dayt.panel.switch", "ff-popup-dayt-switch");
  258.     
  259.     //extended panel
  260.     this.setElement("ff-text-dayf-days", "dayf.panel.days", null); 
  261.     this.setElement("ff-chk-dayf-panel", "dayf.panel.enabled", null); 
  262.     this.setElement("ff-list-dayf-panel-display", "dayf.panel.display", "ff-popup-dayf-panel-display"); 
  263.     this.setElement("ff-list-dayf-panel-mode", "dayf.panel.mode", "ff-popup-dayf-panel-mode");             
  264.   
  265.     //extended tooltip
  266.     this.setElement("ff-chk-dayf-tooltip", "dayf.tooltip.enabled", null);
  267.     this.setElement("ff-list-dayf-tooltip-display", "dayf.tooltip.display", "ff-popup-dayf-tooltip-display");       
  268.  
  269.     //profiles
  270.     this.setElement("ff-chk-profs-rotate", "profile.switch.enabled", null);
  271.     this.setElement("ff-text-profs-rotate", "profile.switch.delay", null);
  272.     
  273.     //links
  274.     this.setElement("ff-list-links-panel", "links.panel", "ff-popup-links-panel");
  275.     this.setElement("ff-list-links-alert", "links.alert", "ff-popup-links-alert");
  276.     this.setElement("ff-list-links-context", "links.context", "ff-popup-links-context");
  277.     this.setElement("ff-list-links-dialog", "links.dialog", "ff-popup-links-dialog");
  278.     
  279.     this.checkLocid();
  280.   },
  281.  
  282.   populateBars: function OptionsModule_populateBars()
  283.   {
  284.     // Creates the menuitems for the toolbar selector.
  285.     var win = getMainWindow();
  286.     var doc = win.document;
  287.     var toolbars = doc.getElementsByTagName("toolbar");
  288.     var statusbars = doc.getElementsByTagName("statusbar");
  289.     var menubars = doc.getElementsByTagName("menubar");
  290.     var popup = document.getElementById("ff-popup-bars");
  291.     var x, bar, item, val, list;
  292.     
  293.     // first remove the toolbars already there...
  294.     while (popup.hasChildNodes())
  295.       popup.removeChild(popup.firstChild);
  296.           
  297.     toolbars = concat(toolbars, statusbars);
  298.     toolbars = concat(toolbars, menubars);
  299.     for (x=0; x<toolbars.length; x++) {
  300.       bar = toolbars[x];
  301.       
  302.       //do not include find toolbar
  303.       if (bar.getAttribute("id") == "FindToolbar")
  304.         continue;
  305.              
  306.       item = document.createElement("menuitem");
  307.       item.setAttribute("id", bar.getAttribute("id"));
  308.       item.value = bar.getAttribute("id");         
  309.       if (bar.hasAttribute("toolbarname"))
  310.         item.setAttribute("label", bar.getAttribute("toolbarname"));
  311.       else
  312.         item.setAttribute("label", bar.getAttribute("id"));                 
  313.       popup.appendChild(item);
  314.     }
  315.     
  316.     this.setElement("ff-list-bars", "general.bar", "ff-popup-bars");    
  317.   },
  318.  
  319.   populatePositions: function OptionsModule_populatePositions()
  320.   {
  321.     if (!document.getElementById("ff-list-bars").selectedItem) {
  322.       setPref("general.bar", "status-bar");
  323.       setPref("general.position", -1);
  324.       this.setElement("ff-list-bars", "general.bar", "ff-popup-bars");
  325.     }
  326.     
  327.     var barid = document.getElementById("ff-list-bars").selectedItem.getAttribute("id");
  328.     var win = getMainWindow();
  329.     var doc = win.document;
  330.     var bar = doc.getElementById(barid);
  331.  
  332.     if (!bar)
  333.       this._max = 0;
  334.     else {
  335.       var len = bar.childNodes.length;
  336.     
  337.       //don't include ourself in count
  338.       if (doc.getElementById("ff-box") && doc.getElementById("ff-box").parentNode == bar)
  339.         len--;
  340.     
  341.       this._max = len;     
  342.     }
  343.  
  344.     var val = getPref("general.position");
  345.     var val2 = getPref("general.bar");
  346.     var text = document.getElementById("ff-text-position");
  347.     var radio = document.getElementsByAttribute("group", "position");
  348.     var group = document.getElementById("ff-group-position");
  349.     var x, el;
  350.     
  351.     //set max value
  352.     text.value = this._max;
  353.     
  354.     //mark always last
  355.     if (val == -1) {
  356.       for (x=0; x < radio.length; x++) {
  357.         if (parseInt(radio[x].value) == val) {
  358.           group.selectedItem = radio[x];
  359.           break;
  360.         }
  361.       }
  362.     }
  363.     
  364.     //mark specific position
  365.     else {
  366.       for (x=0; x < radio.length; x++) {
  367.         if (parseInt(radio[x].value) != -1) {
  368.           group.selectedItem = radio[x];
  369.           break;
  370.         }
  371.       }    
  372.       if (barid != val2) {
  373.         text.value = this._max;
  374.       } else {
  375.         if (val < 0)
  376.           text.value = this._max;
  377.         else if (val > this._max)
  378.           text.value = 0;
  379.         else
  380.           text.value = val; 
  381.       }
  382.     }
  383.     
  384.     // update the error label
  385.     el = document.getElementById("ff-text-position-valid");
  386.     el.setAttribute("value", "0-"+this._max);
  387.     
  388.     //revalidate position
  389.     var comp = this;
  390.     window.setTimeout(function() { comp.validate(); }, 10);
  391.   },
  392.   
  393.   populateValidLabels: function OptionsModule_populateValidLabels() 
  394.   {  
  395.     var el;
  396.     
  397.     el = document.getElementById("ff-text-position-valid");
  398.     el.setAttribute("value", "0-"+this._max);
  399.     
  400.     el = document.getElementById("ff-text-swa-slider-valid");
  401.     el.setAttribute("value", "0-16");
  402.     
  403.     el = document.getElementById("ff-text-cc-slider-valid");
  404.     el.setAttribute("value", "0-16");
  405.     
  406.     el = document.getElementById("ff-text-dayf-days-valid");
  407.     el.setAttribute("value", "0-8");
  408.     
  409.     el = document.getElementById("ff-text-profs-rotate-valid");
  410.     el.setAttribute("value", "0-480");
  411.   },
  412.   
  413.   setElement: function OptionsModule_setElement(aName, aPref, aGroup)
  414.   {
  415.     var x, els;
  416.     
  417.     var el = document.getElementById(aName);
  418.     var val = getPref(aPref);
  419.     switch (el.localName) {
  420.       case "checkbox":
  421.         el.checked = val;
  422.         break;
  423.       case "textbox":
  424.         el.value = this._decodeValue(val);
  425.         break;
  426.       case "menulist":
  427.         els = document.getElementById(aGroup).childNodes;        
  428.         for (x=0; x < els.length; x++) {
  429.           if (((typeof val == "number") ? parseInt(els[x].value) : els[x].value) == val) {
  430.             el.selectedItem = els[x];
  431.             break;
  432.           }
  433.         }      
  434.         break;            
  435.       case "radiogroup":
  436.         els = document.getElementsByAttribute("group", aGroup);        
  437.         for (x=0; x < els.length; x++) {
  438.           if (((typeof val == "number") ? parseInt(els[x].value) : els[x].value) == val) {
  439.             el.selectedItem = els[x];
  440.             break;
  441.           }
  442.         }      
  443.         break;
  444.     }  
  445.   },
  446.   
  447.   setOption: function OptionsModule_setOption(aName, aPref, aType)
  448.   {
  449.     var el = document.getElementById(aName);
  450.     var val;
  451.     switch (el.localName) {
  452.       case "checkbox":
  453.         val = el.checked;
  454.         break;
  455.       case "textbox":
  456.         val = (aType == "Int") ? parseInt(el.value) : this._encodeValue(el.value);
  457.         break;
  458.       case "menulist":
  459.       case "radiogroup":
  460.         val = (aType == "Int") ? parseInt(el.selectedItem.value) : this._encodeValue(el.selectedItem.value);
  461.         break;
  462.     }
  463.     setPref(aPref, val);
  464.   },
  465.   
  466.   selectProfile: function OptionsModule_selectProfile(aList)
  467.   {
  468.     var id = aList.selectedItem.getAttribute("value");
  469.     var popup = document.getElementById("ff-popup-profs");
  470.     popup.hidePopup();
  471.   
  472.     this._prfSvc.current = this._prfSvc.getItem(id);
  473.   },
  474.   
  475.   validate: function OptionsModule_validate()
  476.   {
  477.     //remove error indicators
  478.     for (var i=0; i < this._errors.length; i++)
  479.       this._errors[i].removeAttribute("error");
  480.     this._errors = [];
  481.     
  482.     //check location code
  483.     var el = document.getElementById("ff-text-code");
  484.     if ((el.value == "") || (el.value == "00000"))
  485.       return this.markError(el, 0);
  486.     
  487.     //check position
  488.     el = document.getElementById("ff-text-position");
  489.     var el2 = document.getElementById("ff-text-position-valid");
  490.     if (isNaN(parseInt(el.value)) || el.value < 0 || el.value > this._max)
  491.       return this.markError(el, 0, el2);
  492.       
  493.     //check swa slider
  494.     el = document.getElementById("ff-text-swa-slider");
  495.     el2 = document.getElementById("ff-text-swa-slider-valid");
  496.     if (isNaN(parseInt(el.value)) || el.value < 0 || el.value > 16)
  497.       return this.markError(el, 1, el2);
  498.     
  499.     //check cc slider
  500.     el = document.getElementById("ff-text-cc-slider");
  501.     el2 = document.getElementById("ff-text-cc-slider-valid");
  502.     if (isNaN(parseInt(el.value)) || el.value < 0 || el.value > 16)
  503.       return this.markError(el, 3, el2);
  504.     
  505.     //check extended days
  506.     el = document.getElementById("ff-text-dayf-days");
  507.     el2 = document.getElementById("ff-text-dayf-days-valid");
  508.     if (isNaN(parseInt(el.value)) || el.value < 0 || el.value > 8)
  509.       return this.markError(el, 5, el2);
  510.       
  511.     //check profiles rotat
  512.     el = document.getElementById("ff-text-profs-rotate");
  513.     el2 = document.getElementById("ff-text-profs-rotate-valid");
  514.     if (isNaN(parseInt(el.value)) || el.value < 0 || el.value > 480)
  515.       return this.markError(el, 6, el2);      
  516.  
  517.     //return valid      
  518.     return true;
  519.   },
  520.  
  521.   markError: function OptionsModule_markError(aEl, aIndex, aE2)
  522.   {
  523.     // aE2 is optional: xul object containing a description that will be shown
  524.     //get page list  
  525.     var list = document.getElementById("ff-list-pages");
  526.     
  527.     //mark element
  528.     aEl.setAttribute("error", "true");
  529.     if (aE2)
  530.       aE2.setAttribute("error", "valid");
  531.       // set to valid so css rules don't interfere
  532.     
  533.     //switch to page
  534.     list.selectedItem = list.childNodes[aIndex];     
  535.     this.switchPage(list);
  536.     
  537.     //add to error array
  538.     this._errors.push(aEl);
  539.     if (aE2)
  540.       this._errors.push(aE2);
  541.     
  542.     return false;
  543.   },
  544.   
  545.   accept: function OptionsModule_accept(aClose)
  546.   {
  547.     if (!this.validate())
  548.       return;
  549.  
  550.     this.updateOptions();
  551.     
  552.     //make sure we save profile
  553.     this._prfSvc.setItem(this._prfSvc.current);
  554.     
  555.     if (aClose)  
  556.       window.close();
  557.     else
  558.       document.getElementById("apply").setAttribute("disabled", "true");
  559.   },
  560.  
  561.   updateOptions: function OptionsModule_updateOptions()
  562.   {
  563.     //general
  564.     this.setOption("ff-text-code", "general.locid", "Char");
  565.     this.setOption("ff-group-units", "units.current", "Complex");
  566.     this.setOption("ff-list-bars", "general.bar", "Char");
  567.     var position = document.getElementById("ff-group-position");
  568.     if (parseInt(position.selectedItem.value) == -1)
  569.       setPref("general.position", -1);
  570.     else
  571.       this.setOption("ff-text-position", "general.position", "Int");
  572.   
  573.     //swa panel
  574.     this.setOption("ff-chk-swa-panel", "swa.panel.enabled", "Bool");
  575.     this.setOption("ff-list-swa-panel-display", "swa.panel.display", "Int");
  576.     
  577.     //swa tooltip
  578.     this.setOption("ff-chk-swa-tooltip", "swa.tooltip.enabled", "Bool");
  579.     this.setOption("ff-list-swa-tooltip-display", "swa.tooltip.display", "Int");
  580.     
  581.     //swa slider
  582.     this.setOption("ff-chk-swa-slider", "swa.slider.enabled", "Bool");
  583.     this.setOption("ff-list-swa-slider-display", "swa.slider.display", "Int");
  584.     this.setOption("ff-text-swa-slider", "swa.slider.freq", "Int");
  585.   
  586.     //radar panel
  587.     this.setOption("ff-chk-radar-panel", "radar.panel.enabled", "Bool");
  588.     this.setOption("ff-list-radar-panel-display", "radar.panel.display", "Int");
  589.     
  590.     //radar tooltip
  591.     this.setOption("ff-chk-radar-tooltip", "radar.tooltip.enabled", "Bool");
  592.     this.setOption("ff-list-radar-tooltip-display", "radar.tooltip.display", "Int");
  593.     
  594.     //hourly panel
  595.     this.setOption("ff-chk-hbh-panel", "hbh.panel.enabled", "Bool");
  596.     
  597.     //5 day panel
  598.     this.setOption("ff-chk-fiveday-panel", "fiveday.panel.enabled", "Bool");
  599.           
  600.     //current conditions panel
  601.     this.setOption("ff-chk-cc-panel", "cc.panel.enabled", "Bool");
  602.     this.setOption("ff-list-cc-panel-display", "cc.panel.display", "Int");
  603.     
  604.     //current conditions tooltip
  605.     this.setOption("ff-chk-cc-tooltip", "cc.tooltip.enabled", "Bool");
  606.     this.setOption("ff-list-cc-tooltip-display", "cc.tooltip.display", "Int");
  607.     
  608.     //current conditions slider
  609.     this.setOption("ff-chk-cc-slider", "cc.slider.enabled", "Bool");
  610.     this.setOption("ff-list-cc-slider-display", "cc.slider.display", "Int");
  611.     this.setOption("ff-text-cc-slider", "cc.slider.freq", "Int");
  612.       
  613.     //today's panel
  614.     this.setOption("ff-chk-dayt-panel", "dayt.panel.enabled", "Bool");
  615.     this.setOption("ff-list-dayt-panel-display", "dayt.panel.display", "Int");
  616.     this.setOption("ff-list-dayt-panel-mode", "dayt.panel.mode", "Int");
  617.       
  618.     //today's tooltip
  619.     this.setOption("ff-chk-dayt-tooltip", "dayt.tooltip.enabled", "Bool");
  620.     this.setOption("ff-list-dayt-tooltip-display", "dayt.tooltip.display", "Int");
  621.   
  622.     //today's switch
  623.     this.setOption("ff-list-dayt-switch", "dayt.panel.switch", "Int");
  624.     
  625.     //extended panel
  626.     this.setOption("ff-text-dayf-days", "dayf.panel.days", "Int");
  627.     this.setOption("ff-chk-dayf-panel", "dayf.panel.enabled", "Bool");
  628.     this.setOption("ff-list-dayf-panel-display", "dayf.panel.display", "Int");
  629.     this.setOption("ff-list-dayf-panel-mode", "dayf.panel.mode", "Int");
  630.       
  631.     //extended tooltip
  632.     this.setOption("ff-chk-dayf-tooltip", "dayf.tooltip.enabled", "Bool");
  633.     this.setOption("ff-list-dayf-tooltip-display", "dayf.tooltip.display", "Int");
  634.     
  635.     //profiles
  636.     this.setOption("ff-chk-profs-rotate", "profile.switch.enabled", "Bool");
  637.     this.setOption("ff-text-profs-rotate", "profile.switch.delay", "Int");
  638.     
  639.     //links
  640.     this.setOption("ff-list-links-panel", "links.panel", "Char");
  641.     this.setOption("ff-list-links-alert", "links.alert", "Char");
  642.     this.setOption("ff-list-links-context", "links.context", "Char");
  643.     this.setOption("ff-list-links-dialog", "links.dialog", "Char");
  644.   },
  645.   
  646.   _encodeValue: function OptionsModule__encodeValue(aValue)
  647.   {
  648.     // only encode the strings
  649.     if (typeof aValue != "string")
  650.       return aValue;
  651.     
  652.     // prepare the quotes so that we can use eval
  653.     return trim(aValue.replace(/"/g,"\\\"").replace(/'/g,"\\\'"));
  654.   },
  655.   
  656.   _decodeValue: function OptionsModule__decodeValue(aValue)
  657.   {
  658.     // only encode the strings
  659.     if (typeof aValue != "string")
  660.       return aValue;
  661.     
  662.     // unescape the quotes
  663.     return trim(aValue.replace(/\\"/g,"\"").replace(/\\'/g,"\'"));
  664.   },
  665.   
  666.   importDOM: function OptionsModule_importDOM()
  667.   {
  668.     var bundle = document.getElementById("ff-bundle-options");   
  669.     var success = this._migSvc.importDOM(window);
  670.     var prompter = getPrompter(window);
  671.     if (!success) {
  672.       var err = this._migSvc.lastError;
  673.       if (err.severity < SEVERITY_ERROR)
  674.         return;
  675.       prompter.alert(err.name, err.message);
  676.       return;
  677.     } else
  678.       prompter.alert(bundle.getString("ff.import.title"), 
  679.                      bundle.getString("ff.import.success"));
  680.                      
  681.     this.populateProfiles();
  682.     this.populateOptions();
  683.   },
  684.   
  685.   exportDOM: function OptionsModule_exportDOM()
  686.   {
  687.     var bundle = document.getElementById("ff-bundle-options");   
  688.     var success = this._migSvc.exportDOM(window);
  689.     var prompter = getPrompter(window);
  690.     if (!success) {
  691.       var err = this._migSvc.lastError;
  692.       if (err.severity < SEVERITY_ERROR)
  693.         return;
  694.       prompter.alert(err.name, err.message);
  695.       return;
  696.     } else
  697.       prompter.alert(bundle.getString("ff.export.title"), 
  698.                      bundle.getString("ff.export.success"));
  699.   },
  700.   
  701.   iconSelect: function OptionsModule_iconSelect()
  702.   {
  703.     var uninstall = document.getElementById("ff-btn-icons-uninstall");
  704.     var select = document.getElementById("ff-btn-icons-select");
  705.     var preview = document.getElementById("ff-preview-image");
  706.     var author = document.getElementById("ff-link-icon-author");
  707.     var version = document.getElementById("ff-lbl-icon-version");
  708.     
  709.     //remove values    
  710.     uninstall.setAttribute("disabled", "true");
  711.     select.setAttribute("disabled", "true");
  712.     preview.src = "chrome://forecastfox/skin/images/preview.png";
  713.     version.value = "";
  714.     author.label = ""; 
  715.     author.removeAttribute("tooltiptext");
  716.     author.href = "";
  717.     
  718.     var list = document.getElementById("ff-list-icons");          
  719.     if (list.selectedIndex < 0)
  720.       return;
  721.       
  722.     //fill out metadata
  723.     var pack = this._icnSvc.getItem(list.selectedItem.value);
  724.     var url = pack.getPreviewURL();
  725.     if (url != "")
  726.       preview.src = url;
  727.     version.value = pack.getProperty("version");
  728.     author.label = pack.getProperty("author");
  729.     author.setAttribute("tooltiptext", pack.getProperty("website"));
  730.     author.href = pack.getProperty("website");
  731.     
  732.     //enable uninstall
  733.     var id = this._icnSvc.current.ID;    
  734.     if (pack.ID != "default")
  735.       uninstall.removeAttribute("disabled");
  736.       
  737.     //enable select
  738.     if (pack.ID != id)
  739.       select.removeAttribute("disabled");
  740.   },
  741.   
  742.   iconInstall: function OptionsModule_iconInstall()
  743.   {
  744.     var prompter = getPrompter(window);
  745.     var bundle = document.getElementById("ff-bundle-options"); 
  746.            
  747.     //get file
  748.     var picker = Cc["@mozilla.org/filepicker;1"].
  749.                  createInstance(Ci.nsIFilePicker);  
  750.     picker.appendFilter(bundle.getString("ff.options.icons.filter"), "*.jar");
  751.     picker.defaultExtension = ".jar";
  752.     picker.init(window, bundle.getString("ff.options.icons.picker"), picker.modeOpen);
  753.     
  754.     // get the file and its contents
  755.     var res = picker.show();
  756.     if (res == picker.returnCancel)
  757.       return;
  758.  
  759.     //perform install
  760.     var rv = this._icnSvc.setItem(picker.file);
  761.     if (!rv)
  762.       prompter.alert(bundle.getString("ff.options.icons.picker"), bundle.getString("ff.icons.failed"));
  763.     else
  764.       prompter.alert(bundle.getString("ff.options.icons.picker"), bundle.getString("ff.icons.success"));
  765.   },
  766.   
  767.   iconUninstall: function OptionsModule_iconUninstall()
  768.   {
  769.     var prompter = getPrompter(window);
  770.     var bundle = document.getElementById("ff-bundle-options"); 
  771.     var list = document.getElementById("ff-list-icons");              
  772.     var name = list.selectedItem.label;
  773.     var current = this._icnSvc.current.id;    
  774.     var id = list.selectedItem.value;    
  775.     var rv = prompter.confirm(bundle.getString("ff.options.icons.picker"), bundle.getFormattedString("ff.icons.uninstall", [name]));
  776.     if (!rv)
  777.       return;
  778.     
  779.     //select default pack
  780.     if (id == current)
  781.       this._icnSvc.current = getItem("default");
  782.     
  783.     //perform uninstall
  784.     try {
  785.       rv = this._icnSvc.deleteItem(id);
  786.     } catch(e) {
  787.       this._dskSvc.log("Icon pack uninstall error.", e, null);
  788.     }
  789.   },
  790.   
  791.   iconSet: function OptionsModule_iconSet()
  792.   {   
  793.     //remove attribute on list items
  794.     var list = document.getElementById("ff-list-icons");              
  795.     for (var x=0; x<list.childNodes.length; x++)
  796.       list.childNodes[x].removeAttribute("icon");
  797.         
  798.     //set icon
  799.     this._icnSvc.current = this._icnSvc.getItem(list.selectedItem.value);   
  800.   },
  801.   
  802.   observe: function OptionsModule_observe(aSubject, aTopic, aData)
  803.   {
  804.     switch (aTopic) {
  805.     
  806.     //profile notification
  807.     case "forecastfox-profiles":
  808.     
  809.       //ignore while loading or batch
  810.       if (this._prfSvc.isLoading || this._prfSvc.isBatch)
  811.         return;
  812.         
  813.       //ignore startBatch notification
  814.       if (aData == "startBatch")
  815.         return;
  816.       
  817.       //current changed, profile added, profile deleted, or end batch  
  818.       this.populateProfiles();
  819.       this.populateOptions();
  820.       this.populateIcons(false);
  821.       break;
  822.       
  823.     //icon notification
  824.     case "forecastfox-icons":
  825.     
  826.       //ignore while loading or batch
  827.       if (this._icnSvc.isLoading || this._icnSvc.isBatch)
  828.         return;
  829.         
  830.       switch (aData) {
  831.       
  832.       //current pack changed
  833.       case "current":
  834.         this.populateIcons(false);
  835.         break;
  836.           
  837.       //icon pack added, deleted, or batch ended
  838.       case "setItem":
  839.       case "deleteItem":
  840.       case "endBatch":
  841.         this.populateIcons(true);
  842.         break;
  843.       }
  844.       break;
  845.     }
  846.   }
  847. };
  848.   
  849. function updateButtons(aEvent)
  850. {
  851.   // don't enable the apply button for button presses
  852.   if (aEvent) { 
  853.     if ((aEvent.originalTarget.localName == "button") ||
  854.         (aEvent.originalTarget.localName == "fflink") ||
  855.         (aEvent.originalTarget.getAttribute("type") == "prof"))
  856.     return;
  857.   }
  858.    
  859.   document.getElementById("apply").removeAttribute("disabled");
  860. }
  861.  
  862. function concat(c1, c2)
  863. {
  864.   // Concats too collections into an array.
  865.   var c3 = new Array(c1.length + c2.length);
  866.   var x,y = 0;
  867.  
  868.   for (x = 0; x < c1.length; x++)
  869.     c3[y++] = c1[x];
  870.  
  871.   for (x = 0; x < c2.length; x++)
  872.     c3[y++] = c2[x];
  873.  
  874.   return c3;
  875. }
  876.  
  877. // trims trailing and leading white space
  878. function trim(aString) { 
  879.   aString = aString.replace(/^\s+/g, "");
  880.   return aString.replace(/\s+$/g, "");
  881. }
  882.